package com.example.demo.config.shiro;

import com.example.demo.config.jwt.JwtFilter;
import com.example.demo.utils.ShiroUtils;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 配置shiro
 */
@Configuration
public class ShiroConfig {

    // 1. 创建 ShiroFilter
    @Bean("shiroFilterFactoryBean")
    public ShiroFilterFactoryBean getshiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){

        ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
        // 设置 安全管理器
        System.out.println("=======ShiroFilterFactoryBean======");
        bean.setSecurityManager(defaultWebSecurityManager);

        Map<String, Filter> filterMap = new LinkedHashMap<>();
        //设置我们自定义的JWT过滤器,不适用 shiro 自带的 过滤器
        filterMap.put("jwt", new JwtFilter());
        bean.setFilters(filterMap);

        // 设置文件资源
        Map<String ,String> filterRuleMap=new HashMap<>();
        // 开放了 login ,和 register 页面
        filterRuleMap.put("/**", "jwt");
        filterRuleMap.put("/person/login","anon");
        filterRuleMap.put("/person/register","anon");
        // 拦截了 /findAll 这个请求 ,这个资源需要 授权加上认证。所以访问不了
//        filterRuleMap.put("/person/findAll","authc");
        // 剩下的两个 路由，因为添加了 注解，所以这里不需要添加 ，也是有用的
        bean.setFilterChainDefinitionMap(filterRuleMap);

        // 如果文件资源没有权限，跳转到那个页面
//        bean.setUnauthorizedUrl("quanxian");

//        bean.setLoginUrl("login");

        return bean;
    }

    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public static DefaultAdvisorAutoProxyCreator getLifecycleBeanPostProcessor() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        // 强制使用cglib
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     * 2. 创建 web 类型的 安全管理器
     * @param realm
     * @return
     */
    @Bean
    DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("getRealm") Realm realm){
        DefaultWebSecurityManager manager=new DefaultWebSecurityManager();

        // 关闭Shiro 自带的session
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        manager.setSubjectDAO(subjectDAO);
        manager.setRealm(realm);

        return manager;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 自定义一个 Realm 管理器
     * @return
     */
    @Bean("getRealm")
    public Realm realm(){
        // 设置算法的密度
//        HashedCredentialsMatcher hashedCredentialsMatcher=new HashedCredentialsMatcher();
        //设置Md5 加密
//        hashedCredentialsMatcher.setHashAlgorithmName(ShiroUtils.hashAlgorithmName);
        // 设置hash 散列度
//        hashedCredentialsMatcher.setHashIterations(ShiroUtils.hashIterations);
        ShiroRealm realm=new ShiroRealm();
//        realm.setCredentialsMatcher(hashedCredentialsMatcher);

        realm.setCacheManager(new ShiroCacheManager());
        // 开启全局缓存
        realm.setCachingEnabled(true);
        realm.setAuthenticationCachingEnabled(true);
        realm.setAuthenticationCacheName("renZhenCache");
        realm.setAuthorizationCachingEnabled(true);
        realm.setAuthorizationCacheName("shouQuanCache");

        return realm;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {//@Qualifier("hashedCredentialsMatcher")
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }
}
